{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.1.3 Element-wise BDDC Preconditioner\n",
    "\n",
    "The element-wise BDDC preconditioner in NGSolve is a good general purpose preconditioner that works well both in the shared memory parallel mode as well as in distributed memory mode. In this tutorial, we discuss this preconditioner, related built-in options, and customization from python.   \n",
    "\n",
    "A simple description of the element-wise BDDC (**B**alancing **D**omain **D**ecomposition preconditioner with **C**onstraints) can be given in the context of Lagrange finite element space $V$: the BDDC preconditoner is constructed on an auxiliary space $\\widetilde{V}$ obtained by connecting only element vertices (leaving edge and face shape functions discontinuous). Although larger, the auxiliary space allows local elimination of edge and face variables. Hence an analogue of the  original matrix $A$ on this space, named $\\widetilde A$, is less expensive to invert.  This inverse is used to construct a preconditioner for $A$ as follows:\n",
    "\n",
    "$$\n",
    "C_{BDDC}^{-1} = R {\\,\\widetilde{A}\\,}^{-1}\\, R^t\n",
    "$$\n",
    "\n",
    "Here, $R$ is the averaging operator for the discontinous edge and face variables. \n",
    "\n",
    "To construct a general purpose BDDC preconditioner, NGSolve generalizes this idea to all its finite element spaces by a classification of degrees of freedom. NGSolve classifies dofs into (condensable) `LOCAL_DOF`s and a remainder that consists of these types: \n",
    "\n",
    "`WIREBASKET_DOF`  \n",
    "`INTERFACE_DOF`\n",
    "\n",
    "*The original finite element space $V$ is obtained by requiring conformity of both the above types of dofs, while the auxiliary space $\\widetilde{V}$ is obtained by requiring conformity of `WIREBASKET_DOF`s only.*\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import netgen.gui\n",
    "# %gui tk\n",
    "from ngsolve import *\n",
    "from ngsolve.la import EigenValues_Preconditioner\n",
    "from netgen.csg import unit_cube\n",
    "from netgen.geom2d import unit_square\n",
    "SetHeapSize(100*1000*1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "mesh = Mesh(unit_cube.GenerateMesh(maxh=0.5))\n",
    "# mesh = Mesh(unit_square.GenerateMesh(maxh=0.5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Built-in options\n",
    "\n",
    "Let us define a simple function to study how the spectrum of the preconditioned matrix changes with various options."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def TestPreconditioner (p, condense=False, **args):\n",
    "    fes = H1(mesh, order=p, **args)\n",
    "    u,v = fes.TnT()\n",
    "    a = BilinearForm(fes, eliminate_internal=condense)\n",
    "    a += SymbolicBFI(grad(u)*grad(v) + u*v)\n",
    "    c = Preconditioner(a, \"bddc\")\n",
    "    a.Assemble()   \n",
    "    return EigenValues_Preconditioner(a.mat, c.mat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 1.00145\n",
      " 1.05935\n",
      " 1.23239\n",
      " ...\n",
      "  21.2736\n",
      " 22.7821\n",
      " 22.9382\n",
      "\n"
     ]
    }
   ],
   "source": [
    "lams = TestPreconditioner(5)\n",
    "print (lams[0:3], \"...\\n\", lams[-3:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is the effect of static condensation on the BDDC preconditioner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 1.00026\n",
      " 1.03169\n",
      " 1.09454\n",
      " ...\n",
      "  4.10312\n",
      " 4.13286\n",
      " 4.24601\n",
      "\n"
     ]
    }
   ],
   "source": [
    "lams = TestPreconditioner(5, condense=True)\n",
    "print (lams[0:3], \"...\\n\", lams[-3:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let us study the effect of a few built-in flags for *finite element spaces* that are useful for tweaking the behavior of the BDDC preconditioner. The effect of these flags varies in two (2D) and three dimensions (3D), e.g., \n",
    "\n",
    "- `wb_fulledges=True`: This option keeps **all** edge-dofs conforming (i.e. they are marked `WIREBASKET_DOF`s). This option is only meaningful in 3D. If used in 2D, the preconditioner becomes a direct solver.\n",
    "\n",
    "- `wb_withedges=True`: This option keeps only the **first** edge-dof conforming (i.e., the first edge-dof is marked `WIREBASKET_DOF` and the remaining edge-dofs are marked `INTERFACE_DOF`s). This is the default in 3D.\n",
    "\n",
    "The complete situation is a bit more complex due to the fact these options  can take three values (True, False, Undefined), can be combined, and space dimension can be 2 or 3. So here is a table with the summary of the effect of these options:\n",
    "\n",
    "| wb_fulledges      |  wb_withedges |  2D    |  3D    |\n",
    "|-------------------|---------------|--------|--------|\n",
    "|   True            |   any value   |  all   |   all  |\n",
    "|   False/Undefined |   Undefined   |  none  |  first |\n",
    "|   False/Undefined |    False      |  none  |  none  |\n",
    "|   False/Undefined |    True       |  first |  first |\n",
    "\n",
    "An entry $X \\in$ {all, none, first} of the last two columns is to be read as follows: $X$ of the edge-dofs is(are) `WIREBASKET_DOF`(s)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is an example of the effect of one of these flag values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 1.00121\n",
      "  1.0817\n",
      " 1.23231\n",
      " ...\n",
      "  25.7229\n",
      "  25.723\n",
      " 27.2163\n",
      "\n"
     ]
    }
   ],
   "source": [
    "lams = TestPreconditioner(5, condense=True, wb_withedges=False)\n",
    "print (lams[0:3], \"...\\n\", lams[-3:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Clearly, the conditioning became less favorable compared to the default. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Customize \n",
    "\n",
    "From within python, we can change the types of degrees of freedom of finite element spaces, thus affecting the behavior of the BDDC preconditioner. \n",
    "\n",
    "You can view the types of dofs in a finite element space as follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number vertices = 21\n",
      "dofs of first edge:  (21, 22)\n",
      "ct[ 0 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 1 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 2 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 3 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 4 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 5 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 6 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 7 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 8 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 9 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 10 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 11 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 12 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 13 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 14 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 15 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 16 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 17 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 18 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 19 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 20 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 21 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 22 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 23 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 24 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 25 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 26 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 27 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 28 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 29 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 30 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 31 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 32 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 33 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 34 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 35 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 36 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 37 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 38 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 39 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 40 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 41 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 42 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 43 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 44 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 45 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 46 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 47 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 48 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 49 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 50 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 51 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 52 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 53 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 54 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 55 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 56 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 57 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 58 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 59 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 60 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 61 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 62 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 63 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 64 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 65 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 66 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 67 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 68 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 69 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 70 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 71 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 72 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 73 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 74 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 75 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 76 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 77 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 78 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 79 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 80 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 81 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 82 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 83 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 84 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 85 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 86 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 87 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 88 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 89 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 90 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 91 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 92 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 93 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 94 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 95 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 96 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 97 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 98 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 99 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 100 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 101 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 102 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 103 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 104 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 105 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 106 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 107 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 108 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 109 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 110 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 111 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 112 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 113 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 114 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 115 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 116 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 117 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 118 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 119 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 120 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 121 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 122 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 123 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 124 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 125 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 126 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 127 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 128 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 129 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 130 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 131 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 132 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 133 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 134 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 135 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 136 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 137 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 138 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 139 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 140 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 141 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 142 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 143 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 144 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 145 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 146 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 147 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 148 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 149 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 150 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 151 ] =  COUPLING_TYPE.WIREBASKET_DOF\n",
      "ct[ 152 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 153 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 154 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 155 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 156 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 157 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 158 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 159 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 160 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 161 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 162 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 163 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 164 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 165 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 166 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 167 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 168 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 169 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 170 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 171 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 172 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 173 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 174 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 175 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 176 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 177 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 178 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 179 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 180 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 181 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 182 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 183 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 184 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 185 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 186 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 187 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 188 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 189 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 190 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 191 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 192 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 193 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 194 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 195 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 196 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 197 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 198 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 199 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 200 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 201 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 202 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 203 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 204 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 205 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 206 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 207 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 208 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 209 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 210 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 211 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 212 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 213 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 214 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 215 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 216 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 217 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 218 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 219 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 220 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 221 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 222 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 223 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 224 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 225 ] =  COUPLING_TYPE.INTERFACE_DOF\n",
      "ct[ 226 ] =  COUPLING_TYPE.INTERFACE_DOF\n"
     ]
    }
   ],
   "source": [
    "fes = H1(mesh, order=3)\n",
    "print (\"number vertices =\", mesh.nv)\n",
    "print (\"dofs of first edge: \", fes.GetDofNrs(NodeId(EDGE,0)))\n",
    "for i in range(fes.ndof):\n",
    "    print (\"ct[\",i,\"] = \", fes.CouplingType(i) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9.876864325521144"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lams = TestPreconditioner (8, condense=True)\n",
    "max(lams)/min(lams)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We may modify the dof types as follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6.717426419118481"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fes = H1(mesh, order=8)\n",
    "u,v = fes.TnT()\n",
    "\n",
    "for ed in mesh.edges:\n",
    "    dofs = fes.GetDofNrs(ed)\n",
    "    for d in dofs:\n",
    "        fes.SetCouplingType(d, COUPLING_TYPE.INTERFACE_DOF)\n",
    "\n",
    "    # Set the first two edge dofs to be conforming\n",
    "    fes.SetCouplingType(dofs[0], COUPLING_TYPE.WIREBASKET_DOF)\n",
    "    fes.SetCouplingType(dofs[1], COUPLING_TYPE.WIREBASKET_DOF)\n",
    "\n",
    "a = BilinearForm(fes, eliminate_internal=True)\n",
    "a += SymbolicBFI(grad(u)*grad(v) + u*v)\n",
    "c = Preconditioner(a, \"bddc\")\n",
    "a.Assemble()\n",
    "\n",
    "lams=EigenValues_Preconditioner(a.mat, c.mat)\n",
    "max(lams)/min(lams)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
